package com.samphanie.auiu.admin.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.samphanie.auiu.admin.domain.dto.AllocResourceDto;
import com.samphanie.auiu.admin.domain.vo.ResourceVo;
import com.samphanie.auiu.admin.service.ISysMenuResourceService;
import com.samphanie.auiu.admin.service.ISysResourceService;
import com.samphanie.auiu.admin.service.ISysRoleService;
import com.samphanie.auiu.common.constants.AuiuConstants;
import com.samphanie.auiu.common.service.IRedisService;
import com.samphanie.auiu.mbg.mapper.SysResourceMapper;
import com.samphanie.auiu.mbg.model.SysMenuResource;
import com.samphanie.auiu.mbg.model.SysResource;
import com.samphanie.auiu.mbg.model.SysRole;
import com.samphanie.auiu.mbg.model.SysRoleResource;
import com.samphanie.auiu.mbg.utils.PageUtils;
import lombok.RequiredArgsConstructor;
import lombok.val;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 资源Service业务层处理
 *
 * @author zsy
 * @date 2021-05-18
 */
@Service
@RequiredArgsConstructor
public class SysResourceServiceImpl extends ServiceImpl<SysResourceMapper, SysResource> implements ISysResourceService {

    private final IRedisService redisService;
    private final ISysMenuResourceService menuResourceService;
    @Resource
    @Lazy
    private ISysRoleService roleService;

    /**
     * 查询资源列表
     *
     * @param query
     * @return 资源
     */
    @Override
    public List<SysResource> selectSysResourceList(Map<String, String> query) {
        return baseMapper.selectSysResourceList(query);
    }

    @Override
    public PageUtils listPage(Map<String, Object> query) {
        LambdaQueryWrapper<SysResource> queryWrapper = new LambdaQueryWrapper<>();
        PageUtils.startPage(query);
        val resourceList = list();
        val pageUtils = new PageUtils(resourceList);
        val resourceVos = resourceList.stream().map(item -> {
            if (StrUtil.isNotBlank(item.getMethod())) {
                item.setMethod(item.getMethod().toUpperCase());
            }
            ResourceVo resourceVo = new ResourceVo();
            BeanUtils.copyProperties(item, resourceVo);
            return resourceVo;
        }).collect(Collectors.toList());
        pageUtils.setList(resourceVos);
        return pageUtils;
    }

    @Override
    public List<ResourceVo> listOperationsByMenuId(Long menuId) {
        List<SysMenuResource> menuResources = menuResourceService.listByMenuId(menuId);
        if (CollUtil.isNotEmpty(menuResources)) {
            val resourceIds = menuResources.stream().map(SysMenuResource::getResourceId).collect(Collectors.toSet());
            val resources = listByIds(resourceIds);
            return resources.stream().map(item -> {
                val resourceVo = new ResourceVo();
                BeanUtils.copyProperties(item, resourceVo);
                return resourceVo;
            }).collect(Collectors.toList());
        }
        return Collections.emptyList();
    }

    @Override
    public boolean addResource(List<ResourceVo> operations) {
        val resources = operations.stream().map(item -> {
            SysResource resource = new SysResource();
            BeanUtils.copyProperties(item, resource);
            return resource;
        }).collect(Collectors.toList());

        return saveBatch(resources);
    }

    @Transactional
    @Override
    public boolean allocResource(AllocResourceDto allocResourceDto) {
        // 先删除原有关系
        menuResourceService.deleteByMenuId(allocResourceDto.getMenuId());
        // 批量插入新关系
        val resourceIds = allocResourceDto.getResourceIds();
        if (CollUtil.isNotEmpty(resourceIds)) {
            Set<SysMenuResource> menuResources = allocResourceDto.getResourceIds().stream().map(item -> SysMenuResource.builder()
                    .menuId(allocResourceDto.getMenuId())
                    .resourceId(item)
                    .build()).collect(Collectors.toSet());
            return menuResourceService.saveBatch(menuResources);
        }
        return true;
    }

    /**
     * 初始化资源角色规则
     */
    @Override
    public Map<String, List<String>> initResourceRolesMap() {
        Map<String, List<String>> resourceRoleMap = new TreeMap<>();
        List<SysResource> resourceList = list();
        List<SysRole> roleList = roleService.list();
        List<SysRoleResource> roleResources = roleService.getRoleResourceRelations();
        for (SysResource resource : resourceList) {
            Set<Long> roleIds = roleResources.stream().filter(item -> item.getResourceId().equals(resource.getId()))
                    .map(SysRoleResource::getRoleId)
                    .collect(Collectors.toSet());
            roleIds.add(1L);
            List<String> roleNames = roleList.stream().filter(item -> roleIds.contains(item.getId()))
                    .map(item -> AuiuConstants.ROLE_PREFIX + item.getRoleName())
                    .collect(Collectors.toList());

            resourceRoleMap.put(resource.getPath(), roleNames);
        }

        redisService.del(AuiuConstants.RESOURCE_ROLES_MAP_KEY);
        redisService.hSetAll(AuiuConstants.RESOURCE_ROLES_MAP_KEY, resourceRoleMap);
        return resourceRoleMap;
    }

}
